Operating-system access control allows restricting access to protected resources based on the identities of the authenticated user who is executing a program. Modern run-time environments, such as Java and the Microsoft .NET Common Language Runtime (CLR), in which the programs under execution are obtained by dynamically assembling components, have made it necessary to extend the notion of authenticated user. In such systems, there is the need for a code provider to undergo an authentication and authorization process much the same way as the users who execute the final program. At run time, when different components are dynamically combined to form a program, a component provider can behave as an active attacker and violate the integrity of the system by injecting into the program a component that performs operations that the system administrator did not intend to authorize, such as reading private information from the user's home directory, opening a network connection, and communicating that information to a remote server.
A component can authenticate itself based on its origin in the network and the digital signature applied by the component provider before distribution. The system administrator assigns “permissions” to authenticated components. A permission is the right to access a restricted resource or to perform a security-sensitive operation. At run time, when a component attempts, directly or indirectly, to access a restricted resource or to perform a security-sensitive operation, the underlying run-time environment will demand that the component prove possession of the necessary permission.
Once components are assembled to form a program, a system administrator installing the program configures its access-control policy. In the software lifecycle, this challenge is faced also by component developers and providers, who are encouraged to publish permission recommendations for their components before distributing them, and system administrators, who are supposed to define access-control policies at deployment time. A policy that is too permissive constitutes a violation of the Principle of Least Privilege, which establishes that a user or program should never be granted more permissions than those strictly required to function correctly. If the policy is too restrictive, the program will not function properly due to run-time authorization failures. Source code may not be available, so manual code inspection, besides being tedious, time consuming and error prone, may not even be an option.
One alternative technique is dynamic analysis. With this technique, a component is tested, initially with no permissions. Any attempt by the component to directly or indirectly access a restricted resource will result in a run-time authorization failure. Typically, each failure is logged, and the access-control policy is updated by granting the component the missing permissions, assuming that it is safe to do so. The program is then restarted. This process is reiterated until no more authorization failures are found. In general, however, there is no guarantee that the access-control policy obtained at the end of this process will be sufficient to execute the program without authorization failures. Absence of a complete suite of test cases can leave some execution paths undiscovered until deployment, thereby exposing the deployed program to unjustified authorization failures. Furthermore, executing a potentially malicious program, even just for testing, can be harmful.